From 1b1044b6392373ac86ff659c976dc499802d5abb Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Thu, 20 Mar 2014 17:55:33 -0700 Subject: [PATCH] Encoding and decoding now in libcargo Commands can now call a simple function (execute_main) with some type params, and get flags and stdin converted into their expected structs automatically. Commands that return a json-serializable struct will also get that struct automatically serialized into the output. Additionally, error handling is now handled in a central location. If a command returns a CargoError, its message will be printed (soon in color!) and its exit code will be used to exit the process. --- src/bin/cargo-read-manifest.rs | 17 ++++------- src/bin/cargo-rustc.rs | 23 +++----------- src/cargo/mod.rs | 55 ++++++++++++++++++++++++++++++---- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/src/bin/cargo-read-manifest.rs b/src/bin/cargo-read-manifest.rs index ce2215c8a..a5ed0e49a 100644 --- a/src/bin/cargo-read-manifest.rs +++ b/src/bin/cargo-read-manifest.rs @@ -8,9 +8,8 @@ extern crate toml; use hammer::FlagConfig; use serialize::Decoder; -use serialize::json::Encoder; use toml::from_toml; -use cargo::{Manifest,LibTarget,ExecTarget,Project,CargoResult,ToCargoError,execute_main}; +use cargo::{Manifest,LibTarget,ExecTarget,Project,CargoResult,ToCargoError,execute_main_without_stdin}; use std::path::Path; #[deriving(Decodable,Encodable,Eq,Clone,Ord)] @@ -38,10 +37,10 @@ struct ReadManifestFlags { impl FlagConfig for ReadManifestFlags {} fn main() { - execute_main::(execute); + execute_main_without_stdin::(execute); } -fn execute(flags: ReadManifestFlags) -> CargoResult<()> { +fn execute(flags: ReadManifestFlags) -> CargoResult> { let manifest_path = flags.manifest_path; let root = try!(toml::parse_from_file(manifest_path.clone()).to_cargo_error(format!("Couldn't parse Toml file: {}", manifest_path), 1)); @@ -49,18 +48,12 @@ fn execute(flags: ReadManifestFlags) -> CargoResult<()> { let (lib, bin) = normalize(&toml_manifest.lib, &toml_manifest.bin); - let manifest = Manifest{ + Ok(Some(Manifest { root: try!(Path::new(manifest_path.clone()).dirname_str().to_cargo_error(format!("Could not get dirname from {}", manifest_path), 1)).to_owned(), project: toml_manifest.project, lib: lib, bin: bin - }; - - let encoded: ~str = Encoder::str_encode(&manifest); - - println!("{}", encoded); - - Ok(()) + })) } fn normalize(lib: &Option<~[SerializedLibTarget]>, bin: &Option<~[SerializedExecTarget]>) -> (~[LibTarget], ~[ExecTarget]) { diff --git a/src/bin/cargo-rustc.rs b/src/bin/cargo-rustc.rs index 8967c6ce2..3c0a9b0d7 100644 --- a/src/bin/cargo-rustc.rs +++ b/src/bin/cargo-rustc.rs @@ -6,14 +6,11 @@ extern crate hammer; extern crate serialize; extern crate cargo; -use hammer::FlagConfig; use std::os::args; use std::io; use std::io::process::{Process,ProcessConfig,InheritFd}; -use serialize::json; -use serialize::Decodable; use std::path::Path; -use cargo::{Manifest,CargoResult,CargoError,ToCargoError,execute_main}; +use cargo::{Manifest,CargoResult,CargoError,ToCargoError,NoFlags,execute_main}; /** cargo-rustc -- ...args @@ -22,22 +19,10 @@ use cargo::{Manifest,CargoResult,CargoError,ToCargoError,execute_main}; */ fn main() { - execute_main::(execute); + execute_main::(execute); } -#[deriving(Decodable,Eq,Clone,Ord)] -struct RustcFlags; - -impl FlagConfig for RustcFlags {} - -fn execute(_: RustcFlags) -> CargoResult<()> { - let mut reader = io::stdin(); - let input = try!(reader.read_to_str().to_cargo_error(~"Cannot read stdin to a string", 1)); - - let json = try!(json::from_str(input).to_cargo_error(format!("Cannot parse json: {}", input), 1)); - let mut decoder = json::Decoder::new(json); - let manifest: Manifest = Decodable::decode(&mut decoder); - +fn execute(_: NoFlags, manifest: Manifest) -> CargoResult> { let Manifest{ root, lib, bin, .. } = manifest; let (crate_type, out_dir) = if lib.len() > 0 { @@ -78,7 +63,7 @@ fn execute(_: RustcFlags) -> CargoResult<()> { fail!("Failed to execute") } - Ok(()) + Ok(None) } fn join(path: &Path, part: ~str) -> ~str { diff --git a/src/cargo/mod.rs b/src/cargo/mod.rs index 33f5a0169..30d216295 100644 --- a/src/cargo/mod.rs +++ b/src/cargo/mod.rs @@ -6,7 +6,8 @@ extern crate serialize; extern crate hammer; -use serialize::{Decoder,Decodable}; +use serialize::{Decoder,Encoder,Decodable,Encodable,json}; +use std::io; use std::fmt; use std::fmt::{Show,Formatter}; use hammer::{FlagDecoder,FlagConfig}; @@ -84,22 +85,54 @@ impl ToCargoError for Option { } } -pub fn execute_main>(exec: fn(T) -> CargoResult<()>) { - fn call>(exec: fn(T) -> CargoResult<()>) -> CargoResult<()> { +trait RepresentsFlags : FlagConfig + Decodable {} +impl> RepresentsFlags for T {} + +trait RepresentsJSON : Decodable {} +impl > RepresentsJSON for T {} + +#[deriving(Decodable)] +pub struct NoFlags; + +impl FlagConfig for NoFlags {} + +pub fn execute_main<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable>>(exec: fn(T, U) -> CargoResult>) { + fn call<'a, T: RepresentsFlags, U: RepresentsJSON, V: Encodable>>(exec: fn(T, U) -> CargoResult>) -> CargoResult> { + let flags = try!(flags_from_args::()); + let json = try!(json_from_stdin::()); + + exec(flags, json) + } + + process_executed(call(exec)) +} + +pub fn execute_main_without_stdin<'a, T: RepresentsFlags, V: Encodable>>(exec: fn(T) -> CargoResult>) { + fn call<'a, T: RepresentsFlags, V: Encodable>>(exec: fn(T) -> CargoResult>) -> CargoResult> { let flags = try!(flags_from_args::()); + exec(flags) } - match call(exec) { + process_executed(call(exec)) +} + +fn process_executed<'a, T: Encodable>>(result: CargoResult>) { + match result { Err(e) => { let _ = write!(&mut std::io::stderr(), "{}", e.message); std::os::set_exit_status(e.exit_code as int); }, - Ok(_) => () + Ok(encodable) => { + encodable.map(|encodable| { + let encoded: ~str = json::Encoder::str_encode(&encodable); + println!("{}", encoded); + }); + } } } -fn flags_from_args>() -> CargoResult { +fn flags_from_args() -> CargoResult { let mut decoder = FlagDecoder::new::(std::os::args().tail()); let flags: T = Decodable::decode(&mut decoder); @@ -108,3 +141,13 @@ fn flags_from_args>() -> CargoResult { None => Ok(flags) } } + +fn json_from_stdin() -> CargoResult { + let mut reader = io::stdin(); + let input = try!(reader.read_to_str().to_cargo_error(~"Cannot read stdin to a string", 1)); + + let json = try!(json::from_str(input).to_cargo_error(format!("Cannot parse json: {}", input), 1)); + let mut decoder = json::Decoder::new(json); + + Ok(Decodable::decode(&mut decoder)) +} -- 2.30.2